/*
 * @file     g_rtc.c
 * @brief    This file contains all the functions prototypes for the RTC firmware library.
 *
 * Change Logs:
 * Date           Author             Version        Notes
 * 2021-05-28     xubo               V1.0.0         the first version
 */

/* Includes -----------------------------------------------------------------*/
#include "g_rtc.h"

/* Exported functions -------------------------------------------------------*/
/**
 * @method RTC_IsReady
 * @brief  Check whether rtc is ready or not
 * @param  None
 * @retval The status of RTC ready flag
 */
static G_FlagStatus RTC_IsReady(void)
{
    if (ENABLE == MSYSCTRL->LPM_BUSY_CFG.bit.RTC_EN)//RTC MODE
    {
        return SET;
    }
    return RESET;
}

/**
 * @method G_RTC_Init
 * @brief  RTC module initializes the vector
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @retval result of operation
 */
G_ErrorStatus G_RTC_Init(RTC_TypeDef *RTCx)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    if (RESET == RTC_IsReady())
    {
        return ERROR;
    }

//    G_LPM_AccessCode(ENABLE);
//    G_LPM_RegisterClk(ENABLE);

    MLPM->RTC_LSE_CTRL.bit.EN = ENABLE;
    RTCx->EN.reg = ENABLE;

    return SUCCESS;
}

/**
 * @method G_RTC_ResetCounter
 * @brief  Reset RTC counter value
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @retval None
 */
void G_RTC_ResetCounter(RTC_TypeDef *RTCx)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    RTCx->TIME.reg = 0;
}

/**
 * @method G_RTC_GetCounter
 * @brief  Get RTC counter value
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @retval RTC counter value
 */
uint32_t G_RTC_GetCounter(RTC_TypeDef *RTCx)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    uint32_t CurrentCounter = 0;

    CurrentCounter = RTCx->TIME.reg;

    return CurrentCounter;
}

/**
 * @method G_RTC_SetAlarm
 * @brief  Set RTC alarm value
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @param  AlarmValue: the new RTC alarm value
 * @retval None
 */
void G_RTC_SetAlarm(RTC_TypeDef *RTCx, uint32_t AlarmValue)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    RTCx->ALARM.reg = AlarmValue;
}

/**
 * @method G_RTC_SetRefRegister
 * @brief  Set RTC refernece value
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @param  RefValue: the new RTC refernece value
 * @retval None
 */
void G_RTC_SetRefRegister(RTC_TypeDef *RTCx, uint32_t RefValue)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    RTCx->TIME.reg = RefValue;
}

/**
 * @method G_RTC_GetRefRegister
 * @brief  Get RTC refernece value
 * @param  RTCx : Select the RTC module to use
 *     @arg MRTCLSI
 *     @arg MRTCLSE
 * @retval RTC refernece value
 */
uint32_t G_RTC_GetRefRegister(RTC_TypeDef *RTCx)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    return RTCx->TIME.reg;
}

/**
 * @method G_RTC_ITConfig
 * @brief  Enable or disable RTC interrupt
 * @param  rtc_irqx: RTC interrupt trigger source selection
 *     @arg RTC_SECOND_IRQ
 *     @arg RTC_ALARM_IRQ
 *     @arg RTC_ALL_IRQ
 * @param  NewState: new state of the RTC interrupt
 *         This parameter can be ENABLE or DISABLE
 * @retval None
 */
void G_RTC_ITConfig(RTC_TypeDef *RTCx, uint32_t rtc_irqx, G_FunctionalState NewState)
{
    _ASSERT(IS_RTC_SEL(RTCx));
    _ASSERT(IS_FUNCTIONAL_STATE(NewState));

    if (RTCx == MRTCLSI)
    {
        MSECURE->RTC_IE.bit.LSI_IE = ENABLE;
    }
    else
    {
        MSECURE->RTC_IE.bit.LSE_IE = ENABLE;
    }

    if (DISABLE != NewState)
    {
        RTCx->IE.reg |= rtc_irqx;
    }
    else
    {
        RTCx->IE.reg &= ~rtc_irqx;
    }
}

/**
 * @method RTC_LesClkConfig
 * @brief  Select clk source for RTCLSE and Enable or disable RTC LSECLK
 * @param  RTCLSE_CLKSOURCE_TypeDef :Default set RTCLSE_CLKSOURCE_LSI32K
 *     @arg RTCLSE_CLKSOURCE_LSI32K
 *     @arg RTCLSE_CLKSOURCE_LSE32K
 * @param  G_FunctionalState :ENABLE or DISABLE RTCLSE
 *      @arg ENABLE
 *      @arg DISABLE
 * @retval None
 */
void G_RTC_LseClkConfig(uint8_t RTCLSE_ClkSource, G_FunctionalState NewState)
{
    _ASSERT(IS_RTCLSE_CLKSOURCE_SEL(RTCLSE_ClkSource));

	G_LPM_AccessCode(ENABLE);
	G_LPM_RegisterClk(ENABLE);

    MLPM->RTC_LSE_CTRL.bit.SEL = RTCLSE_ClkSource;
    MLPM->XO32K.bit.DA_LPM_XO32K_EN = NewState;
    MLPM->XO32K.bit.RG_LPM_XO32K_DISCONNECT = DISABLE;
    MLPM->RTC_LSE_CTRL.bit.EN = NewState;
}

/**
 * @method G_RTC_ClearITPendingBit
 * @brief  Clear RTC interrupt pending bit
 * @param  rtc_irqx: RTC interrupt trigger source selection
 *     @arg RTC_SECOND_IRQ
 *     @arg RTC_ALARM_IRQ
 *     @arg RTC_ALL_IRQ
 * @retval None
 */
void G_RTC_ClearITPendingBit(RTC_TypeDef *RTCx, uint32_t rtc_irqx)
{
    _ASSERT(IS_RTC_SEL(RTCx));

    RTCx->IRQ_STATUS.reg = rtc_irqx;
}

/**
 * @method G_RTC_GetITStatus
 * @brief  Check whether the RTC interrupt has occurred or not
 * @param  None
 * @retval RTC interrupt trigger source selection
 *     rtcx_irq = 1 is MRTCLSE, or rtcx_irq = 0 is MRTCLSI
 *     G_RTC_IRQ_TypeDef : MRTCLSE or MRTCLSI
 *     @arg RTC_ALARM_IRQ
 *     @arg RTC_SECURITY_IRQ
 *     @arg RTC_ALL_IRQ
 */
G_RTC_IRQ_TypeDef G_RTC_GetITStatus(void)
{
    G_RTC_IRQ_TypeDef irqx;
    memset(&irqx, 0, sizeof(irqx));

    if (SET == MSECURE->RTC_IE.bit.LSE_IRQ)
    {
        irqx.rtclse_irq = SET;
        if ((MRTCLSE->IRQ_STATUS.reg & RTC_SECOND_IRQ) != 0)
        {
            irqx.rtclse_sec_irq = SET;
        }
        if ((MRTCLSE->IRQ_STATUS.reg & RTC_ALARM_IRQ) != 0)
        {
            irqx.rtclse_alarm_irq = SET;
        }
    }
    if (SET == MSECURE->RTC_IE.bit.LSI_IRQ)
    {
        irqx.rtclsi_irq = SET;
        if ((MRTCLSI->IRQ_STATUS.reg & RTC_SECOND_IRQ) != 0)
        {
            irqx.rtclsi_sec_irq = SET;
        }
        if ((MRTCLSI->IRQ_STATUS.reg & RTC_ALARM_IRQ) != 0)
        {
            irqx.rtclsi_alarm_irq = SET;
        }
    }

    return irqx;
}

/**
 * @method G_RTC_Calibration
 * @brief  Get rtc Calibration value.
 * @param  None
 * @retval rtc Calibration value
 */
void G_RTC_Calibration(void)
{
    uint8_t counter = 0;
    uint32_t cali_cnt = 0;
    uint32_t cali_time = 0;//ns
    uint32_t osc32k_freq = 0;//hz
    uint8_t osc32k_cali_time = 10;
    G_SYSCTRL_PER3Gpio1ClkCtrl(PLL_HSE_48M,SYSCTRL_PER3_Div2);
    MLPM->XO32K.bit.DA_LPM_XO32K_EN = ENABLE;
    MLPM->XO32K.bit.RG_LPM_XO32K_DISCONNECT = DISABLE;
    MLPM->RTC_LSE_CTRL.bit.SEL = RESET;
    *(volatile uint8_t *)(0xf8427) = (osc32k_cali_time << 4); //osc32k_cali_time 2 ^cal_time
    *(volatile uint8_t *)(0xf8427) |= 0x01;
    delay_us(1);
    *(volatile uint8_t *)(0xf8427) &= ~0x01; //cali start
    delay_ms(50);
    while (((*(volatile uint8_t *)(0xf8427) >> 1) & 0x01) != TRUE)
    {
        if (counter >= 20)
        {
            return ;
        }
        counter++;
        delay_ms(50);
    }
    cali_cnt = *(volatile uint32_t *)(0xf8424) & 0xffffff; //gpio1 24M
 //   MyPrintf("cali_cnt :0x%x_%d\n", cali_cnt, cali_cnt);
    /*get cali time ns*/
    cali_time = (cali_cnt / 48) * 1000 + (cali_cnt * 1000 / 48) % 1000;
 //   MyPrintf("cali_time :%d ns\n", cali_time);

    osc32k_freq = (1 * 1000 * 1000 * 1000) / (cali_time / (2 << (osc32k_cali_time - 1))) ;
 //   MyPrintf("osc32k_freq :%d hz _ 0x%x\n", osc32k_freq, osc32k_freq);

 //   osc32k_freq -= 512;

 //   MyPrintf("osc32k_freq-512 :%d hz _ 0x%x\n", osc32k_freq, osc32k_freq);
    *(volatile uint32_t*)(0xfaf04) = osc32k_freq;
    return;
}

/************************ (C) COPYRIGHT GKT *****END OF FILE****/
